home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
gnu
/
gpp-1_42.lha
/
g++-1.42.0
/
collect3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-10-19
|
12KB
|
427 lines
/*
* Copyright (C) 1991 Free Software Foundation, Inc.
* collect3.c - derived from collect2.c by Heinz Seidl (hgs@cygnus.com).
*/
/*
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
C++ allows to initialize global variables with arbitrary expressions,
in particular with constructors. This means, that arbitrary pieces of
code have to be executed _before_ `main()' is called and that constructed
objects must be destructed at the end of the program before `exit()' is
called.
For each file with global initialization gcc generates now initialization
and finalization code:
The initialization code has the label: `__GLOBAL_$I$<name>', where <name> is
the name of the first variable to be initialized.
The finitialization code has the label: `__GLOBAL_$D$<name>', where <name>
is the name of the first variable to be destructed.
Since the C runtime system (and the UNIX linkers) don't know about this kind
of initialization, we have to deal with them:
This program "collects" all the entrypoints for initialization and
finalization code and associates them with the labels `__CTOR_LIST__' and
`__DTOR_LIST__' respectively.
Gcc generates code for the call to `main()' witch invokes the initialization
and finalization code.
*/
/*
* The __C/DTOR_LIST__ have the folowing form:
*
* entry_pt * __C/DTOR_LIST__[] = {
* _first_entry_point,
* _second_entry_point,
* ...
* 0
* }
*
* Both lists are in _proper_ order; i.e. the destructor list is in reverse
* order of the constructor list.
*
* In case OLD_FORMAT is defined, init.c understands the format generated by
* gld 1.x and used by gnulib3.
*
* The order is determined by the order of the .o files on the command line
* and how the linker arranges them in the output file.
* It is expected that the linker arranges the con/destructors in reverse
* order as the command line.
* There is no predicable order for files from archives.
*/
static char * rcsId = "$Id: collect3.c,v 1.2 1991/10/03 00:37:07 hgs Exp $";
#if defined (__GNUC__)
#define alloca __builtin_alloca
#else
#define alloca malloc
#endif
#include "config.h"
/* This means no additional `_' is prepended;
but have at least one `_' at the beginning */
#ifdef NO_UNDERSCORES
#define CTOR_MARKER_NAME "_GLOBAL_$I$"
#define DTOR_MARKER_NAME "_GLOBAL_$D$"
#define CDTOR_MARKER_LEN 11
#define FUNCTION_LIST_ADDR "_function_list_addr"
#define FUNCTION_LIST_ADDR_LEN 19
#else
#define CTOR_MARKER_NAME "__GLOBAL_$I$"
#define DTOR_MARKER_NAME "__GLOBAL_$D$"
#define CDTOR_MARKER_LEN 12
#define FUNCTION_LIST_ADDR "__function_list_addr"
#define FUNCTION_LIST_ADDR_LEN 20
#endif
#include <stdio.h>
#define USAGE() do fprintf( stderr, \
"Usage: %s <link-command options>" ## \
"[-- [-t] [-d tmp_dir] [-g gcc-path]]", \
argv[0]); \
while(0);
#define GREP_CMD " grep -v TOR_LIST__"
#define NM_CMD " nm -pg"
/* convert empty string into blank (stupidity of ?printf) */
#define S(str) ((str && *str) ? str : " ")
extern char *mktemp (char *template);
static void error( const char * msg, int line );
#define ERROR(msg) error( msg, __LINE__)
#ifndef PREFIX
#define PREFIX "/usr/unsupported"
#endif
#define const static
/* causes strange bugs */
const char * TMP_DIR = "/usr/tmp";
const char * AOUTXXX = "AOUTXXXXXX";
const char * CDTORXXX = "CDTORXXXXXX";
const char * GCC_FLAGS = "-g -ftraditional";
const char * GCC = PREFIX "/bin/gcc";
#undef const
static char * prog_name = NULL;
/* Linked lists of constructor and destructor names.
*/
struct id
{
char *name;
struct id *next;
};
/* if we link ccrt0 to an object we always need the C/DTOR_LISTS even if they are empty */
static int need_cdtor_list = 0;
main (int argc, char *argv[])
{
char /*const causes strange errors*/* tmp_dir = TMP_DIR;
char CDTOR_filename_c[BUFSIZ], CDTOR_filename_o[BUFSIZ], buf[BUFSIZ];
char AOUT_filename[BUFSIZ];
FILE * pipe_in;
char * outfile = "a.out";
char * arg, ldargs1[BUFSIZ*2], ldargs2[BUFSIZ*2], cmd[BUFSIZ*4];
char * s = ldargs1;
char * debug_str = NULL; /* or `set -x; ' */
int no_rm = 0;
char /* const */* gcc = GCC;
int ret = 0;
ldargs1[0] = '\0'; ldargs2[0] = '\0';
prog_name = argv[0];
/* Parse arguments for the linker
*/
while (arg = *++argv)
{
if (! strcmp (arg, "--"))
{
/* parse the options for collect
*/
while (arg = *++argv)
{
switch ( (int) arg[1])
{
case 'v':
debug_str = "set -x;";
tmp_dir = ".";
break;
case 'd':
tmp_dir = *++argv;
break;
case 'g':
gcc = *++argv;
break;
case 'r':
no_rm = 1;
tmp_dir = ".";
break;
default:
USAGE();
exit(1);
}
}
break; /* get out of arg parsing loop */
}
/* remove output file from command line
*/
if (! strcmp (arg, "-o"))
{
outfile = *++argv;
continue;
}
/* Split the arguments after *rt0.o and before the first .o file
*/
if ( !strcmp (arg + strlen(arg) -2, ".o") )
if (! (strlen( arg) >= 5 && !strcmp (arg+strlen(arg)-5, "rt0.o")) )
s = ldargs2;
strcat (s , " '"); strcat (s, arg); strcat (s, "'");
}
/* Make temp file names.
*/
if (debug_str)
{
tmp_dir = ".";
sprintf( AOUT_filename, "%s", AOUTXXX);
(void) mktemp (AOUT_filename);
}
else
sprintf( AOUT_filename, "%s", outfile); /* we reuse the outfile */
sprintf( buf, "%s/%s", tmp_dir, CDTORXXX);
(void) mktemp (buf);
sprintf (CDTOR_filename_c, "%s.c", buf);
sprintf (CDTOR_filename_o, "%s.o", buf);
/* Load the program, searching all libraries.
* (The introduction of shared libraries fucked the -r option of
* the SunOS linker; therefore we link twice; unless we don't have
* de/constructors).
*/
if ( debug_str)
sprintf (cmd, "%s ld -o %s %s %s",
S(debug_str), AOUT_filename, S(ldargs1), S(ldargs2));
else
sprintf (cmd, "ld -o %s %s %s 2>&1 |" GREP_CMD,
AOUT_filename, S(ldargs1), S(ldargs2));
system( cmd);
/* Examine the namelist with nm and search it for static constructors
* and destructors to call.
* Write the constructor and destructor tables to a .c file.
*/
sprintf (cmd, "%s " NM_CMD " %s", S(debug_str), AOUT_filename);
if (! (pipe_in = popen (cmd, "r"))) ERROR( "popen failed");
ret = write_CDTOR_list (pipe_in, CDTOR_filename_c);
if (pclose (pipe_in)) ERROR( "pclose failed");
if ( ret == 0 && ! need_cdtor_list) exit(0); /* no de/constructors */
/* Compile the constructor and destructor tables.
*/
if ( debug_str )
sprintf (cmd, "%s %s -v -c %s -o %s %s",
S(debug_str), gcc, GCC_FLAGS,
CDTOR_filename_o, CDTOR_filename_c);
else
sprintf (cmd,"%s -c %s -o %s %s",
gcc, GCC_FLAGS, CDTOR_filename_o, CDTOR_filename_c);
system( cmd);
/* Link the tables in with the rest of the program.
*/
sprintf (cmd, "%s ld -o %s %s %s %s",
S(debug_str), outfile, S(ldargs1), CDTOR_filename_o,
S(ldargs2));
system( cmd);
if ( ! debug_str && ! no_rm)
{
unlink (CDTOR_filename_c);
unlink (CDTOR_filename_o);
}
exit(0);
}
int write_CDTOR_list (FILE * pipe_in, char * CDTOR_filename_c)
/*
* Scan the name list of the loaded program for the symbols g++ uses
* for static constructors and destructors. Write their addresses
* into tables which __main() and exit() will call.
* returns 0 iff no de/constructors - otherwise > 0
*/
{
register char *p;
char buf[BUFSIZ];
struct id *newid;
FILE * CDTOR_file;
struct id *constructors = 0;
struct id *destructors = 0, *d_anchor = 0;
#ifdef OLD_FORMAT
int nb_constructors = 0, nb_destructors = 0;
#endif
while (! feof (pipe_in))
{
/* read a line and strip trailing newline */
fgets (buf, sizeof buf, pipe_in);
p = buf + strlen( buf) - 1;
if ( *p == '\n') *p = '\0';
/* If it contains a constructor or destructor name, add the name
* to the appropriate list.
*/
for (p = buf; *p && *p != '_'; p++);
if (! strncmp (p, CTOR_MARKER_NAME, CDTOR_MARKER_LEN))
{
newid = alloca (sizeof *newid);
newid->name = alloca (strlen (p) + 1);
#ifdef NO_UNDERSCORES
strcpy (newid->name, p);
#else
strcpy (newid->name, p+1);
#endif
newid->next = constructors;
constructors = newid;
#ifdef OLD_FORMAT
nb_constructors ++;
#endif
}
else if (! strncmp (p, DTOR_MARKER_NAME, CDTOR_MARKER_LEN))
{
newid = alloca (sizeof *newid);
newid->name = alloca (strlen (p) + 1);
#ifdef NO_UNDERSCORES
strcpy (newid->name, p);
#else
strcpy (newid->name, p+1);
#endif
#ifdef OLD_FORMAT
newid->next = destructors;
destructors = newid;
nb_destructors ++;
#else
newid->next = 0;
if( !d_anchor)
{ d_anchor = destructors = newid; }
else
{
destructors->next = newid;
destructors = newid;
}
#endif
}
else if ( ! need_cdtor_list &&
/* this shows we have ccrt0 and need the C/DTOR_LISTs */
(! strncmp (p, FUNCTION_LIST_ADDR, FUNCTION_LIST_ADDR_LEN)))
need_cdtor_list ++;
}
if ( ! need_cdtor_list && constructors == 0 && destructors == 0 ) return 0;
if (! (CDTOR_file = fopen (CDTOR_filename_c, "w")))
ERROR( "fopen failed");
/* Write the tables as C code */
fprintf (CDTOR_file, "typedef void entry_pt();\n\n");
write_list (CDTOR_file, "entry_pt ", constructors, ";\n");
fprintf (CDTOR_file, "\nentry_pt * __CTOR_LIST__[] = {\n");
#ifdef OLD_FORMAT
fprintf (CDTOR_file, "\t(entry_pt *) %d,\n", nb_constructors);
write_list (CDTOR_file, "\t", constructors, ",\n");
#else
write_list (CDTOR_file, "\t", constructors, ",\n");
#endif
fprintf (CDTOR_file, "\t0\n};\n\n");
#ifdef OLD_FORMAT
write_list (CDTOR_file, "entry_pt ", destructors, ";\n");
#else
write_list (CDTOR_file, "entry_pt ", d_anchor, ";\n");
#endif
fprintf (CDTOR_file, "\nentry_pt * __DTOR_LIST__[] = {\n");
#ifdef OLD_FORMAT
fprintf (CDTOR_file, "\t(entry_pt *) %d,\n", nb_destructors);
write_list (CDTOR_file, "\t", destructors, ",\n");
#else
write_list (CDTOR_file, "\t", d_anchor, ",\n");
#endif
fprintf (CDTOR_file, "\t0\n};\n\n");
if (fclose (CDTOR_file))
ERROR( "fclose failed");
return 1;
}
write_list ( FILE *CDTOR_file, char * prefix, struct id *list, char * suffix)
/*
* Write `prefix', the names on list LIST, `suffix'.
*/
{
if (! list)
return;
write_list ( CDTOR_file, prefix, list->next, suffix);
fprintf ( CDTOR_file, "%s%s%s", prefix, list->name, suffix);
}
static void error( const char * msg, int line )
{
static char buf[BUFSIZ];
sprintf( buf, "%s: %s at %d", prog_name, S(msg), line);
perror( buf);
exit( 1);
}
/* FIXME: the -r option should be enabled (maybe with a flag) on certain machines */
/* FIXME: no fixed size arrays should be used, but xmalloc (see collect-osf) */
/* FIXME: check why const does not work */
/* FIXME: encapsulate prototypes */
/* FIXME: make all external interface names configureable */